﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace UnitTest.Other
{
    public class TestVideo
    {

        public static int GetVideoDuration(string ffmpegfile, string sourceFile)
        {
            try
            {
                using (System.Diagnostics.Process ffmpeg = new System.Diagnostics.Process())
                {
                    String duration;  // soon will hold our video's duration in the form "HH:MM:SS.UU"  
                    String result;  // temp variable holding a string representation of our video's duration  
                    StreamReader errorreader;  // StringWriter to hold output from ffmpeg  

                    // we want to execute the process without opening a shell  
                    ffmpeg.StartInfo.UseShellExecute = false;
                    //ffmpeg.StartInfo.ErrorDialog = false;  
                    ffmpeg.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                    // redirect StandardError so we can parse it  
                    // for some reason the output comes through over StandardError  
                    ffmpeg.StartInfo.RedirectStandardError = true;
                    // set the file name of our process, including the full path  
                    // (as well as quotes, as if you were calling it from the command-line)  
                    ffmpeg.StartInfo.FileName = ffmpegfile;

                    // set the command-line arguments of our process, including full paths of any files  
                    // (as well as quotes, as if you were passing these arguments on the command-line)  
                    ffmpeg.StartInfo.Arguments = "-i " + sourceFile;

                    // start the process  
                    ffmpeg.Start();

                    // now that the process is started, we can redirect output to the StreamReader we defined  
                    errorreader = ffmpeg.StandardError;

                    // wait until ffmpeg comes back  
                    ffmpeg.WaitForExit();

                    // read the output from ffmpeg, which for some reason is found in Process.StandardError  
                    result = errorreader.ReadToEnd();

                    // a little convoluded, this string manipulation...  
                    // working from the inside out, it:  
                    // takes a substring of result, starting from the end of the "Duration: " label contained within,  
                    // (execute "ffmpeg.exe -i somevideofile" on the command-line to verify for yourself that it is there)  
                    // and going the full length of the timestamp  

                    duration = result.Substring(result.IndexOf("Duration: ") + ("Duration: ").Length, ("00:00:00").Length);

                    string[] ss = duration.Split(':');
                    int h = int.Parse(ss[0]);
                    int m = int.Parse(ss[1]);
                    int s = int.Parse(ss[2]);
                    return h * 3600 + m * 60 + s;
                }
            }
            catch (System.Exception ex)
            {
                return 60;
            }
        }

        public static void ProcessVideo(string startFile, string args, int timeout, out string standardOutput,
    out string standardError)
        {
            using (var process = new ProcessExecutor(startFile, args, timeout))
            {
                process.Execute(out standardOutput, out standardError);
            }
        }

    }




    

    public class ProcessExecutor : IDisposable
    {
        private readonly StringBuilder error;
        private readonly AutoResetEvent errorWaitHandle;
        private readonly StringBuilder output;
        private readonly int timeout;
        private AutoResetEvent outputWaitHandle;
        private Process process;

        public ProcessExecutor(string startFile, string args, int timeout = 0)
        {
            process = new Process();
            //设置进程启动信息属性StartInfo，这是ProcessStartInfo类
            process.StartInfo.FileName = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(startFile));
            process.StartInfo.Arguments = Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(args));

            process.StartInfo.UseShellExecute = false;
            //提供的标准输出流只有2k,超过大小会卡住;如果有大量输出,就读出来
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.CreateNoWindow = true;

            output = new StringBuilder();
            error = new StringBuilder();

            outputWaitHandle = new AutoResetEvent(false);
            errorWaitHandle = new AutoResetEvent(false);

            this.timeout = timeout;

            RegisterToEvents();
        }

        public void Dispose()
        {
            UnregisterFromEvents();

            if (process != null)
            {
                process.Dispose();
                process = null;
            }
            if (errorWaitHandle != null)
            {
                errorWaitHandle.Close();
                outputWaitHandle = null;
            }
            if (outputWaitHandle != null)
            {
                outputWaitHandle.Close();
                outputWaitHandle = null;
            }
        }

        public void Execute(out string standardOutput, out string standardError)
        {
            process.Start();

            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            if (process.WaitForExit(timeout) &&
                outputWaitHandle.WaitOne(timeout) &&
                errorWaitHandle.WaitOne(timeout))
            {

            }
            else
            {
                // if timeout then kill the procee
                process.Kill();
            }

            standardOutput = output.ToString();
            standardError = error.ToString();
        }

        private void RegisterToEvents()
        {
            process.OutputDataReceived += process_OutputDataReceived;
            process.ErrorDataReceived += process_ErrorDataReceived;
        }

        private void UnregisterFromEvents()
        {
            process.OutputDataReceived -= process_OutputDataReceived;
            process.ErrorDataReceived -= process_ErrorDataReceived;
        }

        private void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data == null)
            {
                errorWaitHandle.Set();
            }
            else
            {
                error.AppendLine(e.Data);
            }
        }

        private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data == null)
            {
                outputWaitHandle.Set();
            }
            else
            {
                output.AppendLine(e.Data);
            }
        }
    }
}
